﻿
// ———————————————————————–
// <copyright file="TestHelper.cs" company="The MITRE Corporation">
//    Copyright (c) 2014 The MITRE Corporation. All rights reserved.
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
// </copyright>
// ———————————————————————–
/////////////////////////////////////////////////////////////////////////////////////////////////
// TestHelper.cs:
//
// A helper file for running tests. Allows you to traverse generator and test classes easily
// through abstraction
//
// Project: NIEMCADTest
// Author:  Lizzie DeYoung - MITRE
/////////////////////////////////////////////////////////////////////////////////////////////////

// Copyright (c) 2014 The MITRE Corporation. All rights reserved.
//
// NOTICE
// This software was produced for the U. S. Government
// under Contract No. FA8721-09-C-0001, and is
// subject to the Rights in Noncommercial Computer Software
// and Noncommercial Computer Software Documentation Clause
// (DFARS) 252.227-7014 (JUN 1995)  
      

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Xml;

namespace NIEMCADTest
{
  /// <summary>
  /// This class performs much of the reflection necessary to get the good and bad values for the nested
  /// data types. It includes methods to
  /// - Get all bad values for a particular data type
  /// - Get a single good value for a particular data type
  /// - Get all good values for a particular data type
  /// </summary>
  class TestHelper
  {
    public  delegate List<TestObject> Operator(TestObject testObject, string xml);

    /// <summary>
    /// Reads in an XML string and return the root XML node.
    /// </summary>
    /// <param name="xml"></param>
    /// <returns></returns>
    public static XmlNode ReadXML(string xml)
    {
      XmlDocument doc = new XmlDocument();
      doc.LoadXml(xml);
      return doc.DocumentElement;
    }

    /// <summary>
    /// Returns a <typeparamref name="TestObject"/> containing a good XML example 
    /// representing <paramref name="type"/>.
    /// </summary>
    /// <param name="type">The data type</param>
    /// <returns>A <typeparamref name="TestObject"/> containing a good XML example 
    /// representing <paramref name="type"/></returns>
    public static TestObject GetAGoodTestObject(Type type)
    {
      List<MethodInfo> methods = TestHelper.GetGoodMethods(type);

      MethodInfo methodInfo = methods[0];
      List<TestObject> list = TestHelper.InvokeMethod(methodInfo, type);

      TestObject testObject = list[0];

      return testObject;
    }

    /// <summary>
    /// Returns a <typeparamref name="TestObject"/> containing all good XML examples 
    /// representing <paramref name="type"/>.
    /// </summary>
    /// <param name="type">The data type</param>
    /// <returns>A list of <typeparamref name="TestObject"/> containing a good XML 
    /// examples representing <paramref name="type"/></returns>
    public static List<TestObject> GetGoodTestObjects(Type type)
    {
      List<TestObject> list = new List<TestObject>();
      List<MethodInfo> methods = TestHelper.GetGoodMethods(type);

      foreach (MethodInfo methodInfo in methods)
      {
        List<TestObject> testObjectList = TestHelper.InvokeMethod(methodInfo, type);
        list.AddRange(testObjectList);
      }

      return list;
    }

    /// <summary>
    /// Returns a <typeparamref name="TestObject"/> containing all bad XML examples 
    /// representing <paramref name="type"/>.
    /// </summary>
    /// <param name="type">The data type</param>
    /// <returns>A list of <typeparamref name="TestObject"/> containing a bad XML 
    /// examples representing <paramref name="type"/></returns>
    public static List<TestObject> GetBadTestObjects(Type type)
    {
      List<TestObject> list = new List<TestObject>();
      List<MethodInfo> methods = TestHelper.GetBadMethods(type);

      foreach (MethodInfo methodInfo in methods)
      {
        List<TestObject> testObjectList = TestHelper.InvokeMethod(methodInfo, type);
        list.AddRange(testObjectList);
      }

      return list;
    }

    private static List<MethodInfo> GetGoodMethods(Type type)
    {
      List<MethodInfo> list = new List<MethodInfo>();
      foreach (MethodInfo methodInfo in type.GetMethods())
      {
        if (methodInfo.Name.StartsWith("GOOD_"))
        {
          list.Add(methodInfo);
        }
      }
      return list;
    }

    private static List<MethodInfo> GetBadMethods(Type type)
    {
      List<MethodInfo> list = new List<MethodInfo>();
      foreach (MethodInfo methodInfo in type.GetMethods())
      {
        if (methodInfo.Name.StartsWith("BAD_"))
        {
          list.Add(methodInfo);
        }
      }
      return list;
    }

    private static List<TestObject> InvokeMethod(MethodInfo methodInfo, Type type)
    {
      object classInstance = Activator.CreateInstance(type, null);
      object result = methodInfo.Invoke(classInstance, null);
      List<TestObject> list = (List<TestObject>)result;

      return list;
    }
  }
}
